/*
 * Copyright (C) 2008 ZXing authors
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.zxing.view;

import com.google.zxing.ResultPoint;
import com.zxing.ResourceTable;
import com.zxing.utils.Log;
import com.zxing.utils.Utils;

import ohos.agp.components.AttrSet;
import ohos.agp.components.Component;
import ohos.agp.render.Canvas;
import ohos.agp.render.Paint;
import ohos.agp.render.PixelMapHolder;
import ohos.agp.utils.Color;
import ohos.agp.utils.Rect;
import ohos.agp.utils.RectFloat;
import ohos.app.Context;
import ohos.eventhandler.EventHandler;
import ohos.eventhandler.EventRunner;
import ohos.eventhandler.InnerEvent;
import ohos.media.image.PixelMap;

import java.util.Collection;

/**
 * 自定义组件实现,扫描功能
 */
public final class ViewfinderView extends Component implements Component.DrawTask {
    private static final long ANIMATION_DELAY = 10L;
    private static final int OPAQUE = 0xFF;

    private Paint paint;
    private int maskColor;

    // 扫描线移动的y
    private int scanLineTop;
    // 扫描线移动速度
    private int SCAN_VELOCITY = 3;
    // 扫描线
    private PixelMap scanLight = null;
    private Collection<ResultPoint> possibleResultPoints;

    private EventHandler eventHandler;

    public ViewfinderView(Context context) {
        this(context, null, 0);
    }

    public ViewfinderView(Context context, FinderSetting setting) {
        super(context, null);
        this.setting = setting;
        init();
        if (setting.getCornerColor() != 0) {
            maskColor = setting.getCornerColor();
        }
        if (setting.getMarginTop() > 0) {
            FRAME_MARGIN_TOP = setting.getMarginTop();
        }
        if (setting.getScanSpeed() > 0) {
            SCAN_VELOCITY = setting.getScanSpeed();
        }
        if (setting.getScanBitmap() != 0) {
            try {
                scanLight = Utils.getPixelmap(getContext(), setting.getScanBitmap());
            } catch (Exception e) {
                Log.error(e.getMessage());
            }
        }

        if (setting.getCornerHeight() > 0) {
            corLength = setting.getCornerHeight();
        }
        if (setting.getCornerWidth() > 0) {
            corWidth = setting.getCornerWidth();
        }

        if (setting.getFrameSize() > 0) {
            frameSize = setting.getFrameSize();
        }
    }

    public ViewfinderView(Context context, AttrSet attrSet) {
        this(context, attrSet, 0);
    }

    public ViewfinderView(Context context, AttrSet attrSet, String styleName) {
        super(context, attrSet, styleName);
        init();
    }

    public ViewfinderView(Context context, AttrSet attrSet, int resId) {
        super(context, attrSet, resId);
        init();
    }

    private FinderSetting setting;

    private void init() {
        maskColor = Utils.getColor(getContext(), ResourceTable.Color_viewfinder_mask);
        paint = new Paint();
        addDrawTask(this);
        try {
            scanLight = Utils.getPixelmap(getContext(), ResourceTable.Media_scan_light);
        } catch (Exception e) {
            Log.error(e.getMessage());
        }
        corWidth = 15;
        corLength = 65;
        eventHandler =
                new EventHandler(EventRunner.current()) {
                    @Override
                    public void processEvent(InnerEvent event) {
                        invalidate();
                    }
                };
    }

    @Override
    public void onDraw(Component component, Canvas canvas) {
        if (framingRect == null) {
            framingRect = getFirstFramingRect();
        }
        int width = getWidth();
        int height = getHeight();
        drawDarkened(canvas, framingRect);
        drawFrameBounds(canvas, framingRect);
        drawScanLight(canvas, framingRect);
        eventHandler.sendEvent(0, ANIMATION_DELAY);
    }

    private void drawDarkened(Canvas canvas, Rect frame) {
        paint.setColor(new Color(maskColor));
        paint.setAlpha(0.6f);
        int width = getWidth();
        int height = getHeight();
        canvas.drawRect(new RectFloat(0, 0, width, frame.top), paint);
        canvas.drawRect(new RectFloat(0, frame.top, frame.left, frame.bottom), paint);
        canvas.drawRect(new RectFloat(frame.right, frame.top, width, frame.bottom), paint);
        canvas.drawRect(new RectFloat(0, frame.bottom, width, height), paint);
    }

    private int corWidth;
    private int corLength;

    private void drawFrameBounds(Canvas canvas, Rect frame) {
        paint.setColor(new Color(Utils.getColor(getContext(), ResourceTable.Color_inner_corner_color)));
        paint.setAlpha(1.0f);
        paint.setStyle(Paint.Style.FILL_STYLE);

        // 左上角
        canvas.drawRect(new RectFloat(frame.left, frame.top, frame.left + corWidth, frame.top + corLength), paint);
        canvas.drawRect(new RectFloat(frame.left, frame.top, frame.left + corLength, frame.top + corWidth), paint);
        // 右上角
        canvas.drawRect(new RectFloat(frame.right - corWidth, frame.top, frame.right, frame.top + corLength), paint);
        canvas.drawRect(new RectFloat(frame.right - corLength, frame.top, frame.right, frame.top + corWidth), paint);
        // 左下角
        canvas.drawRect(
                new RectFloat(frame.left, frame.bottom - corLength, frame.left + corWidth, frame.bottom), paint);
        canvas.drawRect(
                new RectFloat(frame.left, frame.bottom - corWidth, frame.left + corLength, frame.bottom), paint);
        // 右下角
        canvas.drawRect(
                new RectFloat(frame.right - corWidth, frame.bottom - corLength, frame.right, frame.bottom), paint);
        canvas.drawRect(
                new RectFloat(frame.right - corLength, frame.bottom - corWidth, frame.right, frame.bottom), paint);
    }

    /**
     * 绘制移动扫描线
     *
     * @param canvas canvas
     * @param frame frame
     */
    private void drawScanLight(Canvas canvas, Rect frame) {
        if (scanLight == null) {
            return;
        }
        if (scanLineTop == 0) {
            scanLineTop = frame.top;
        }

        if (scanLineTop >= frame.bottom - 30) {
            scanLineTop = frame.top;
        } else {
            scanLineTop += SCAN_VELOCITY;
        }
        RectFloat scanRect = new RectFloat(frame.left, scanLineTop, frame.right, scanLineTop + 30);
        PixelMapHolder holder = new PixelMapHolder(scanLight);
        canvas.drawPixelMapHolderRect(
                holder,
                new RectFloat(0, 0, scanLight.getImageInfo().size.width, scanLight.getImageInfo().size.height),
                scanRect,
                paint);
    }

    /**
     * 重绘
     */
    public void drawViewfinder() {
        invalidate();
    }

    /**
     * set rect
     * @param framingRect r
     */
    public void setFramingRect(Rect framingRect) {
        this.framingRect = framingRect;
    }

    /**
     * rect
     * @return rect
     */
    public Rect getFramingRect() {
        return framingRect;
    }

    private Rect framingRect;
    private int FRAME_MARGIN_TOP = -1;
    private int frameSize;

    private Rect getFirstFramingRect() {
        try {
            if (frameSize == 0) {
                frameSize = Math.min(getWidth(), getHeight()) * 2 / 3;
            }
            int leftOffset = (getWidth() - frameSize) / 2;
            int topOffset;

            if (FRAME_MARGIN_TOP != -1) {
                topOffset = FRAME_MARGIN_TOP;
            } else {
                topOffset = (getHeight() - frameSize) / 2;
            }
            framingRect = new Rect(leftOffset, topOffset, leftOffset + frameSize, topOffset + frameSize);
            return framingRect;
        } catch (Exception e) {
            Log.error(e.getMessage());
            return null;
        }
    }


    /**
     * Draw a bitmap with the result points highlighted instead of the live scanning display.
     *
     * @param barcode An image of the decoded barcode.
     */
    public void drawResultBitmap(PixelMap barcode) {
        scanLight = barcode;
        invalidate();
    }

    /**
     * addPossibleResultPoint
     * @param point 点
     */
    public void addPossibleResultPoint(ResultPoint point) {
        possibleResultPoints.add(point);
    }
}
